﻿using FunArts.EasyDevOps.Shared.Models.SshClient.NginxClient;
using FunArts.EasyDevOps.Shared.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FunArts.EasyDevOps.Rcl.Repertories.Impl
{
    /// <summary>
    /// Nginx配置文件仓储
    /// </summary>
    public class NginxConfigRepertory: INginxConfigRepertory
    {
        /// <summary>
        /// 保存Nginx配置到文件
        /// </summary>
        /// <param name="config"></param>
        /// <param name="filePath"></param>
        public void SaveConfigToFile(NginxServerConfig config, string filePath)
        {
            var configText = GenerateConfig(config);
            File.WriteAllText(filePath, configText);
        }
        /// <summary>
        /// 从文件加载Nginx配置
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public NginxServerConfig LoadConfigFromFile(string filePath)
        {
            var configText = File.ReadAllText(filePath);
            return ParseConfig(configText);
        }

        /// <summary>
        /// Nginx配置解析
        /// </summary>
        public NginxServerConfig ParseConfig(string configText)
        {
            var config = new NginxServerConfig()
            {
                AdditionalDirectives = new List<string>(),
                LocationList = new List<NginxServerConfigLocation>()
            };

            var lines = configText.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            var serverBlockDepth = 0;
            var currentLocation = null as NginxServerConfigLocation;
            var currentBlock = null as List<string>;

            for (int i = 0; i < lines.Length; i++)
            {
                var line = lines[i].Trim();

                // 跳过注释和空行
                if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
                    continue;

                // 处理server块开始
                if (line.StartsWith("server") && line.EndsWith("{"))
                {
                    serverBlockDepth++;
                    continue;
                }

                // 只在server块内处理
                if (serverBlockDepth == 0)
                    continue;

                // 处理块结束
                if (line == "}")
                {
                    if (currentLocation != null)
                    {
                        // 结束location块
                        config.LocationList.Add(currentLocation);
                        currentLocation = null;
                    }
                    else if (serverBlockDepth > 0)
                    {
                        serverBlockDepth--;
                    }
                    continue;
                }

                // 处理location块
                if (line.StartsWith("location") && line.Contains("{"))
                {
                    var locationPath = line.Substring("location".Length)
                        .Trim()
                        .Split(new[] { '{' }, StringSplitOptions.RemoveEmptyEntries)[0]
                        .Trim();

                    currentLocation = new NginxServerConfigLocation
                    {
                        Path = locationPath,
                        AdditionalDirectives = new List<string>()
                    };
                    continue;
                }

                // 如果在location块中
                if (currentLocation != null)
                {
                    ParseLocationDirective(currentLocation, line);
                    continue;
                }

                // 解析普通指令
                ParseServerDirective(config, line);
            }

            return config;
        }

        private void ParseServerDirective(NginxServerConfig config, string line)
        {
            var parts = SplitDirective(line);
            if (parts.Length == 0) return;

            switch (parts[0])
            {
                case "listen":
                    config.ListenPort = int.Parse(parts[1].TrimEnd(';'));
                    config.EnableHttps = line.Contains("ssl");
                    break;
                case "server_name":
                    config.ServerName = string.Join(" ", parts.Skip(1)).TrimEnd(';');
                    break;
                case "root":
                    config.RootPath = parts[1].TrimEnd(';');
                    break;
                case "index":
                    config.IndexFiles = string.Join(" ", parts.Skip(1))
                        .TrimEnd(';')
                        .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                        .ToList();
                    break;
                case "ssl_certificate":
                    config.SslCertificatePath = parts[1].TrimEnd(';');
                    break;
                case "ssl_certificate_key":
                    config.SslCertificateKeyPath = parts[1].TrimEnd(';');
                    break;
                default:
                    // 不是已知指令，作为附加指令保存
                    if (!line.Trim().StartsWith("{") && !line.Trim().StartsWith("}"))
                    {
                        config.AdditionalDirectives.Add(line.TrimEnd(';'));
                    }
                    break;
            }
        }

        private void ParseLocationDirective(NginxServerConfigLocation location, string line)
        {
            var parts = SplitDirective(line);
            if (parts.Length == 0) return;

            switch (parts[0])
            {
                case "proxy_pass":
                    location.ProxyPass = parts[1].TrimEnd(';');
                    break;
                case "proxy_set_header":
                    if (line.Contains("Upgrade $http_upgrade"))
                        location.IsWebSocket = true;
                    location.AdditionalDirectives.Add(line.TrimEnd(';'));
                    break;
                default:
                    if (!string.IsNullOrWhiteSpace(line) &&
                        !line.StartsWith("{") &&
                        !line.StartsWith("}"))
                    {
                        location.AdditionalDirectives.Add(line.TrimEnd(';'));
                    }
                    break;
            }
        }

        /// <summary>
        /// 分割配置文件
        /// </summary>
        private string[] SplitDirective(string line)
        {
            return line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
        }

        /// <summary>
        /// 生成配置
        /// </summary>
        public string GenerateConfig(NginxServerConfig config)
        {
            var sb = new StringBuilder();
            var indent = "    ";

            sb.AppendLine("server {");

            // 基本配置
            AppendIfNotEmpty(sb, indent, "listen", config.ListenPort.ToString());
            AppendIfNotEmpty(sb, indent, "server_name", config.ServerName);
            AppendIfNotEmpty(sb, indent, "root", config.RootPath);

            if (config.IndexFiles.Count > 0)
            {
                sb.AppendLine($"{indent}index {string.Join(" ", config.IndexFiles)};");
            }

            if (config.EnableHttps)
            {
                AppendIfNotEmpty(sb, indent, "ssl_certificate", config.SslCertificatePath);
                AppendIfNotEmpty(sb, indent, "ssl_certificate_key", config.SslCertificateKeyPath);
            }

            // 附加指令
            foreach (var directive in config.AdditionalDirectives)
            {
                sb.AppendLine($"{indent}{directive};");
            }

            // Location块
            foreach (var location in config.LocationList)
            {
                sb.AppendLine();
                sb.AppendLine($"{indent}location {location.Path} {{");

                AppendIfNotEmpty(sb, indent + indent, "proxy_pass", location.ProxyPass);
                sb.AppendLine($"{indent}{indent}proxy_http_version 1.1;");

                if (location.IsWebSocket)
                {
                    sb.AppendLine($"{indent}{indent}proxy_set_header Upgrade $http_upgrade;");
                    sb.AppendLine($"{indent}{indent}proxy_set_header Connection 'upgrade';");
                }

                foreach (var directive in location.AdditionalDirectives)
                {
                    sb.AppendLine($"{indent}{indent}{directive};");
                }

                sb.AppendLine($"{indent}}}");
            }

            sb.AppendLine("}");

            return sb.ToString();
        }

        private void AppendIfNotEmpty(StringBuilder sb, string indent, string directive, string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                sb.AppendLine($"{indent}{directive} {value};");
            }
        }
    }
}
